package com.bensonbasement.snorflux.server.world;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import org.apache.mina.core.session.IoSession;

import com.bensonbasement.snorflux.commands.ItemData;
import com.bensonbasement.snorflux.commands.VerbInfo;
import com.bensonbasement.snorflux.memory.WorldElementInfo;
import com.bensonbasement.snorflux.messages.fromserver.ReportMessage;
import com.bensonbasement.snorflux.messages.fromserver.CommandRequestMessage;
import com.bensonbasement.snorflux.messages.fromserver.DeleteInfoMessage;
import com.bensonbasement.snorflux.messages.fromserver.IFromServerMessage;
import com.bensonbasement.snorflux.messages.fromserver.InfoUpdateMessage;
import com.bensonbasement.snorflux.messages.fromserver.JoinedMessage;
import com.bensonbasement.snorflux.messages.fromserver.PlayerInfo;
import com.bensonbasement.snorflux.messages.fromserver.VisibilityUpdateMessage;
import com.bensonbasement.snorflux.messages.fromserver.reports.Report;
import com.bensonbasement.snorflux.server.ContentRepository;
import com.bensonbasement.snorflux.server.verbs.Verb;
import com.bensonbasement.snorflux.server.verbs.WalkVerb;

public class PlayerBrain extends Brain {
	
	private final String playerName;
	private transient IoSession session = null;
	
	public PlayerBrain(String playerName, BrainTeam team) {
		super(team);
		this.playerName = playerName;
	}
	
	@Override
	public void receiveInfo(WorldElementInfo info) {
		InfoUpdateMessage message = new InfoUpdateMessage(info);
		sendMessage(message);
	}
	
	@Override
	public void receiveReport(Report report) {
		ReportMessage message = new ReportMessage(report);
		sendMessage(message);
	}
	
	@Override
	public void deleteInfo(long worldElementID) {
		DeleteInfoMessage message = new DeleteInfoMessage(worldElementID);
		sendMessage(message);
	}
	
	@Override
	public void updateVisibility(Set<Long> newlyVisibleSpaceIDs,
			Set<Long> newlyNonVisibleSpaceIDs) {
		VisibilityUpdateMessage message = new VisibilityUpdateMessage(newlyVisibleSpaceIDs, newlyNonVisibleSpaceIDs);
		sendMessage(message);
	}
	
	public void sendCommandRequest(Actor currentActor) {
		//List<VerbInfo> possibleVerbInfos = currentActor.getWorld()
		List<ItemData> inventory = new LinkedList<ItemData>();
		for (SmallEntity item : currentActor.getSmallEntities()) {
			List<VerbInfo> verbInfos = new LinkedList<VerbInfo>();
			for (Verb verb : item.getAllVerbs()) {
				VerbInfo info = verb.render(currentActor, item);
				if (info != null) {
					verbInfos.add(info);
				}
			}
			ItemData data = new ItemData(item.getName(),item.getGlyph(),verbInfos);
			inventory.add(data);
		}
		List<ItemData> stuffHere = new LinkedList<ItemData>();
		for (SmallEntity item : currentActor.getLocation().getSmallEntities()) {
			List<VerbInfo> verbInfos = new LinkedList<VerbInfo>();
			for (Verb verb : item.getAllVerbs()) {
				VerbInfo info = verb.render(currentActor, item);
				if (info != null) {
					verbInfos.add(info);
				}
			}
			ItemData data = new ItemData(item.getName(),item.getGlyph(),verbInfos);
			stuffHere.add(data);
		}
		VerbInfo moveVerb = null;
		List<VerbInfo> abilities = new LinkedList<VerbInfo>();
		for (Verb verb : ContentRepository.getInstance().getObjectlessVerbs()) {
			VerbInfo info = verb.render(currentActor,null);
			if (info != null) {
				// TODO: Use some other criteria for this...
				if (verb == WalkVerb.WALK) {
					moveVerb = info;
				}
				else {
					abilities.add(info);
				}
			}
		}
		CommandRequestMessage message = new CommandRequestMessage(currentActor.getWorldElementID(),currentActor.getAP(),moveVerb,abilities,stuffHere,inventory);
		sendMessage(message);
	}
	
	public boolean hasSession() {
		return (session != null);
	}
	
	public IoSession getSession() {
		return session;
	}
	
	public void joinToSession(IoSession session) {
		if (session == null) {
			throw new RuntimeException ("Trying to invoke joinToSession with null session.");
		}
		this.session = session;
		// TODO: Send entire memory to client.
		// (after the brain itself HAS a memory).
	}
	
	public void sendJoinedMessage(PlayerInfo[] playerList) {
		JoinedMessage joinedMessage = new JoinedMessage(playerName,playerList,getBrainTeam().getMemory());
		sendMessage(joinedMessage);
	}
	
	public void sendMessage(IFromServerMessage message) {
		if (session != null) {
			session.write(message);
		}
	}
	
	public void disconnectAndClearSession() {
		if (session != null) {
			session.close(false);
		}
		session = null;
	}
	
	public String getPlayerName() {
		return playerName;
	}
	
	/**
	 * Called when the object is deserialized.
	 */
	private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
		in.defaultReadObject();
		session = null;
	}
}
